﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Security;
using System.Xml;
using Notoric.Model.Collections;
using Notoric.Model.Internal;
using Notoric.Model.Packaging;
using Notoric.Model.Validation;

namespace Notoric.Model.Elements
{
    /// <summary>
    /// Implements the composition model element.
    /// </summary>
    /// <remarks>
    /// A composition holds musical data.
    /// </remarks>
    public class CompositionElement : ModelElement
    {
        #region Constructors

        /// <summary>
        /// Creates a new <see cref="CompositionElement"/> instance.
        /// </summary>
        /// <param name="packagePart">
        /// <para>
        /// Type: <see cref="CompositionPart"/>
        /// </para>
        /// <para>
        /// The package part that owns this element.
        /// </para>
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="packagePart"/> is <see langword="null"/>.
        /// </exception>
        internal CompositionElement(CompositionPart packagePart)
            : base(packagePart)
        {
            composers = new ElementCollection<PersonElement>(this, composersElement);
            lyricists = new ElementCollection<PersonElement>(this, lyricistsElement);
            coda = new ElementCollection<MeasureElement>(this, codaElement);
            measures = new ElementCollection<MeasureElement>(this, measuresElement);
            parts = new ElementCollection<PartDescriptorElement>(this, partsElement);
            repetitionsCollection = new ElementCollection<RepetitionElement>(this, repetitionsElement);
            repetitions = new ReadOnlyCollection<RepetitionElement>(repetitionsCollection);
            referencingSections = new ElementCollection<MusicSectionReferenceElement>(this, referencingSectionsElement);
            connectors = new ElementCollection<ConnectorElement>(this, connectorsElement);

            coda.CollectionChanged += new EventHandler<NotifyCollectionChangedEventArgs>(coda_CollectionChanged);
            measures.CollectionChanged += new EventHandler<NotifyCollectionChangedEventArgs>(measures_CollectionChanged);
            parts.CollectionChanged += new EventHandler<NotifyCollectionChangedEventArgs>(parts_CollectionChanged);
            connectors.CollectionChanged += new EventHandler<NotifyCollectionChangedEventArgs>(connectors_CollectionChanged);
        }

        /// <summary>
        /// Creates a new <see cref="CompositionElement"/> instance.
        /// </summary>
        /// <param name="packagePart">
        /// <para>
        /// Type: <see cref="CompositionPart"/>
        /// </para>
        /// <para>
        /// The package part that owns this element.
        /// </para>
        /// </param>
        /// <param name="element">
        /// <para>
        /// Type: <see cref="XmlElement"/>
        /// </para>
        /// <para>
        /// The element that represents this object.
        /// </para>
        /// </param>
        internal CompositionElement(CompositionPart packagePart, XmlElement element)
            : base(packagePart, element)
        {
            composersElement = element["composers", PackageVocabulary.PackageNamespaceUri];
            lyricistsElement = element["lyricists", PackageVocabulary.PackageNamespaceUri];
            codaElement = element[PackageVocabulary.CodaElementName, PackageVocabulary.PackageNamespaceUri];
            measuresElement = element[PackageVocabulary.MeasureElementName + "s", PackageVocabulary.PackageNamespaceUri];
            partsElement = element[PackageVocabulary.PartDescriptorElementName + "s", PackageVocabulary.PackageNamespaceUri];
            repetitionsElement = element[PackageVocabulary.RepetitionElementName + "s", PackageVocabulary.PackageNamespaceUri];
            connectorsElement = element[PackageVocabulary.ConnectorElementName + "s", PackageVocabulary.PackageNamespaceUri];
            descriptionElement = element["description", PackageVocabulary.PackageNamespaceUri];
            referencingSectionsElement = element[PackageVocabulary.ReferencingSectionsElementName, PackageVocabulary.PackageNamespaceUri];

            composers = new ElementCollection<PersonElement>(this, composersElement);
            lyricists = new ElementCollection<PersonElement>(this, lyricistsElement);
            parts = new ElementCollection<PartDescriptorElement>(this, partsElement);
            coda = new ElementCollection<MeasureElement>(this, codaElement);
            measures = new ElementCollection<MeasureElement>(this, measuresElement);
            repetitionsCollection = new ElementCollection<RepetitionElement>(this, repetitionsElement);
            repetitions = new ReadOnlyCollection<RepetitionElement>(repetitionsCollection);
            connectors = new ElementCollection<ConnectorElement>(this, connectorsElement);
            referencingSections = new ElementCollection<MusicSectionReferenceElement>(this, referencingSectionsElement);

            coda.CollectionChanged += new EventHandler<NotifyCollectionChangedEventArgs>(coda_CollectionChanged);
            measures.CollectionChanged += new EventHandler<NotifyCollectionChangedEventArgs>(measures_CollectionChanged);
            parts.CollectionChanged += new EventHandler<NotifyCollectionChangedEventArgs>(parts_CollectionChanged);
            connectors.CollectionChanged += new EventHandler<NotifyCollectionChangedEventArgs>(connectors_CollectionChanged);

            codaAttribute = element.Attributes[PackageVocabulary.CodaAttribute];
            fineAttribute = element.Attributes[PackageVocabulary.FineAttribute];
            segnoAttribute = element.Attributes[PackageVocabulary.SegnoAttribute];
            dateAttribute = element.Attributes["date"];
            subTitleAttribute = element.Attributes["subtitle"];
            titleAttribute = element.Attributes["title"];

            if (codaAttribute.Value != "0")
                codaSign = measures[ushort.Parse(codaAttribute.Value, PackageVocabulary.PackageCulture.NumberFormat) - 1];
            if (fineAttribute.Value != "0")
                fine = measures[ushort.Parse(fineAttribute.Value, PackageVocabulary.PackageCulture.NumberFormat) - 1];
            if (segnoAttribute.Value != "0")
                segno = measures[ushort.Parse(segnoAttribute.Value, PackageVocabulary.PackageCulture.NumberFormat) - 1];
        }

        #endregion

        #region ModelElement Members

        /// <inheritdoc/>
        protected override XmlElement CreateObjectElement(XmlDocument document)
        {
            var element = document.CreateElement(
                                PackageVocabulary.PackageNamespacePrefix,
                                PackageVocabulary.CompositionElementName,
                                PackageVocabulary.PackageNamespaceUri
                                );

            composersElement = document.CreateElement(
                PackageVocabulary.PackageNamespacePrefix,
                "composers",
                PackageVocabulary.PackageNamespaceUri
                );
            connectorsElement = document.CreateElement(
                PackageVocabulary.PackageNamespacePrefix,
                PackageVocabulary.ConnectorElementName + "s",
                PackageVocabulary.PackageNamespaceUri
                );
            codaElement = document.CreateElement(
                PackageVocabulary.PackageNamespacePrefix,
                PackageVocabulary.CodaElementName,
                PackageVocabulary.PackageNamespaceUri
                );
            descriptionElement = document.CreateElement(
                PackageVocabulary.PackageNamespacePrefix,
                "description",
                PackageVocabulary.PackageNamespaceUri
                );
            lyricistsElement = document.CreateElement(
                PackageVocabulary.PackageNamespacePrefix,
                "lyricists",
                PackageVocabulary.PackageNamespaceUri
                );
            measuresElement = document.CreateElement(
                PackageVocabulary.PackageNamespacePrefix,
                PackageVocabulary.MeasureElementName + "s",
                PackageVocabulary.PackageNamespaceUri
                );
            partsElement = document.CreateElement(
                PackageVocabulary.PackageNamespacePrefix,
                PackageVocabulary.PartDescriptorElementName + "s",
                PackageVocabulary.PackageNamespaceUri
                );
            repetitionsElement = document.CreateElement(
                PackageVocabulary.PackageNamespacePrefix,
                PackageVocabulary.RepetitionElementName + "s",
                PackageVocabulary.PackageNamespaceUri
                );
            referencingSectionsElement = document.CreateElement(
                PackageVocabulary.PackageNamespacePrefix,
                PackageVocabulary.ReferencingSectionsElementName,
                PackageVocabulary.PackageNamespaceUri
                );

            codaAttribute = document.CreateAttribute(PackageVocabulary.CodaAttribute);
            dateAttribute = document.CreateAttribute("date");
            fineAttribute = document.CreateAttribute(PackageVocabulary.FineAttribute);
            segnoAttribute = document.CreateAttribute(PackageVocabulary.SegnoAttribute);
            subTitleAttribute = document.CreateAttribute("subtitle");
            titleAttribute = document.CreateAttribute("title");

            codaAttribute.Value = "0";
            fineAttribute.Value = "0";
            segnoAttribute.Value = "0";

            element.AppendChild(composersElement);
            element.AppendChild(lyricistsElement);
            element.AppendChild(codaElement);
            element.AppendChild(measuresElement);
            element.AppendChild(partsElement);
            element.AppendChild(repetitionsElement);
            element.AppendChild(connectorsElement);
            element.AppendChild(descriptionElement);
            element.AppendChild(referencingSectionsElement);

            element.Attributes.Append(codaAttribute);
            element.Attributes.Append(fineAttribute);
            element.Attributes.Append(segnoAttribute);
            element.Attributes.Append(dateAttribute);
            element.Attributes.Append(subTitleAttribute);
            element.Attributes.Append(titleAttribute);

            return element;
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// Occurs when the collection of connectors has changed.
        /// </summary>
        /// <param name="sender">Object that has sent the event</param>
        /// <param name="e">Event data</param>
        private void connectors_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Remove || e.Action == NotifyCollectionChangedAction.Replace)
            {
                foreach (ConnectorElement connector in e.OldItems)
                {
                     connector.Start.Connectors.Remove(connector);
                     connector.End.Connectors.Remove(connector);
                }
            }
            if (e.Action == NotifyCollectionChangedAction.Add || e.Action == NotifyCollectionChangedAction.Replace)
            {
                foreach (ConnectorElement connector in e.NewItems)
                {
                    connector.Start.Connectors.Add(connector);
                    connector.End.Connectors.Add(connector);
                }
            }
        }

        /// <summary>
        /// Occurs when the <see cref="Parts"/> collection has changed.
        /// </summary>
        /// <remarks>
        /// <b>Operation:</b><br/>
        /// <list type="table">
        /// <listheader>
        /// <term>
        ///     Change Type
        /// </term>
        /// <description>
        ///     Handler Action
        /// </description>
        /// </listheader>
        /// <item>
        /// <term>
        ///     Add
        /// </term>
        /// <description>
        ///     New items are checked for the owner (must be this <see cref="CompositionElement"/>).
        /// </description>
        /// </item>
        /// <item>
        /// <term>
        ///     Replace
        /// </term>
        /// <description>
        ///     New items are checked for the owner (must be this <see cref="CompositionElement"/>).
        /// </description>
        /// </item>
        /// </list>
        /// </remarks>
        /// <param name="sender">Object that has sent the event</param>
        /// <param name="e">Event data</param>
        private void parts_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Add || e.Action == NotifyCollectionChangedAction.Replace)
            {
                bool invalid = false;

                foreach (PartDescriptorElement descriptor in e.NewItems)
                {
                    if (descriptor.FindOwner<CompositionElement>() != this)
                    {
                        parts.Remove(descriptor);
                        invalid = true;
                    }
                }

                if (invalid)
                    throw new InvalidOperationException("The descriptors added to the CompositionElement's Parts collection must be owned by this CompositionElement and have unique ID!");
            }
        }

        /// <summary>
        /// Occurs when the <see cref="Measures"/> collection has changed.
        /// </summary>
        /// <remarks>
        /// <b>Operation:</b><br/>
        /// <list type="table">
        /// <listheader>
        /// <term>
        ///     Change Type
        /// </term>
        /// <description>
        ///     Handler Action
        /// </description>
        /// </listheader>
        /// <item>
        /// <term>
        ///     Add
        /// </term>
        /// <description>
        ///     Check the owner of the added <see cref="MeasureElement"/>s (must be this <see cref="CompositionElement"/>).<br/>
        ///     Increment the numbers of the subsequent measures in this collection and in <see cref="Coda"/>.
        /// </description>
        /// </item>
        /// <item>
        /// <term>
        ///     Remove
        /// </term>
        /// <description>
        ///     Decrement the numbers of the subsequent measures in this collection and in <see cref="Coda"/>
        /// </description>
        /// </item>
        /// <item>
        ///     Move
        /// </item>
        /// <item>
        ///     Decrement the numbers of the measures in the interval [oldIndex, newIndex) and update the number
        ///     of the measure that was moved.
        /// </item>
        /// <item>
        /// <term>
        ///     Replace
        /// </term>
        /// <description>
        ///     Check the owner of the <see cref="MeasureElement"/>s that replaced the old items (must be this <see cref="CompositionElement"/>).<br/>
        ///     Update their numbers.
        /// </description>
        /// </item>
        /// </list>
        /// </remarks>
        /// <param name="sender">Object that has sent the event</param>
        /// <param name="e">Event data</param>
        private void measures_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                {
                    // First check if ever added measure belongs to this composition.
                    bool invalid = false;

                    foreach (MeasureElement measure in e.NewItems)
                    {
                        if (measure.FindOwner<CompositionElement>() != this)
                        {
                            measures.Remove(measure);
                            invalid = true;
                        }
                    }

                    if (invalid)
                        throw new InvalidOperationException("The measures added to the CompositionElement's Measures collection must be owned by this CompositionElement!");

                    // Update the numbers of the added measures and of all the subsequent measures.
                    ushort number = (ushort)(e.NewStartingIndex + 1);
                    for (int i = e.NewStartingIndex; i < measures.Count; ++i)
                    {
                        measures[i].Number = number;
                        ++number;
                    }
                    for (int i = 0; i < coda.Count; ++i)
                    {
                        coda[i].Number = number;
                        ++number;
                    }

                    break;
                }
                case NotifyCollectionChangedAction.Remove:
                {
                    ushort number = (ushort)(e.OldStartingIndex + 1);
                    for (int i = e.OldStartingIndex; i < measures.Count; ++i)
                    {
                        measures[i].Number = number;
                        ++number;
                    }
                    for (int i = 0; i < coda.Count; ++i)
                    {
                        coda[i].Number = number;
                        ++number;
                    }

                    break;
                }
                case NotifyCollectionChangedAction.Move:
                {
                    int i1, i2;
                    if (e.OldStartingIndex < e.NewStartingIndex)
                    {
                        i1 = e.OldStartingIndex;
                        i2 = e.NewStartingIndex;
                    }
                    else
                    {
                        i1 = e.NewStartingIndex;
                        i2 = e.OldStartingIndex;
                    }
                    ushort number = (ushort)(i1 + 1);
                    for (int i = i1; i <= i2; ++i)
                    {
                        measures[i].Number = number;
                        ++number;
                    }

                    break;
                }
                case NotifyCollectionChangedAction.Replace:
                {
                    bool invalid = false;
                    ushort number = (ushort)(e.OldStartingIndex + 1);
                    
                    foreach (MeasureElement measure in e.NewItems)
                    {
                        if (measure.FindOwner<CompositionElement>() != this)
                        {
                            measures.Remove(measure);
                            invalid = true;
                        }
                        else
                        {
                            measure.Number = number;
                            ++number;
                        }
                    }

                    if (invalid)
                        throw new InvalidOperationException("The measures added to the CompositionElement's Measures collection must be owned by this CompositionElement!");

                    break;
                }
            }

            RaisePropertyChanged("MeasuresCount");
        }

        /// <summary>
        /// Occurs when the <see cref="Coda"/> collection has changed.
        /// </summary>
        /// <remarks>
        /// <b>Operation:</b><br/>
        /// <list type="table">
        /// <listheader>
        /// <term>
        ///     Change Type
        /// </term>
        /// <description>
        ///     Handler Action
        /// </description>
        /// </listheader>
        /// <item>
        /// <term>
        ///     Add
        /// </term>
        /// <description>
        ///     Check the owner of the added <see cref="MeasureElement"/>s (must be this <see cref="CompositionElement"/>).<br/>
        ///     Increment the numbers of the subsequent measures.
        /// </description>
        /// </item>
        /// <item>
        /// <term>
        ///     Remove
        /// </term>
        /// <description>
        ///     Decrement the numbers of the subsequent measures.
        /// </description>
        /// </item>
        /// <item>
        ///     Move
        /// </item>
        /// <item>
        ///     Decrement the numbers of the measures between the old and the new position of the measure 
        ///     and update the number of the measure that was moved.
        /// </item>
        /// <item>
        /// <term>
        ///     Replace
        /// </term>
        /// <description>
        ///     Check the owner of the <see cref="MeasureElement"/>s that replaced the old items (must be this <see cref="CompositionElement"/>).<br/>
        ///     Update their numbers.
        /// </description>
        /// </item>
        /// </list>
        /// </remarks>
        /// <param name="sender">Object that has sent the event</param>
        /// <param name="e">Event data</param>
        private void coda_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                {
                    // First check if ever added measure belongs to this composition.
                    bool invalid = false;

                    foreach (MeasureElement measure in e.NewItems)
                    {
                        if (measure.FindOwner<CompositionElement>() != this)
                        {
                            coda.Remove(measure);
                            invalid = true;
                        }
                    }

                    if (invalid)
                        throw new InvalidOperationException("The measures added to the CompositionElement's Coda collection must be owned by this CompositionElement!");

                    // Update the numbers of the added measures and of all the subsequent measures.
                    ushort number = (ushort)(e.NewStartingIndex + 1);
                    for (int i = e.NewStartingIndex; i < coda.Count; ++i)
                    {
                        coda[i].Number = number;
                        ++number;
                    }

                    break;
                }
                case NotifyCollectionChangedAction.Remove:
                {
                    ushort number = (ushort)(e.OldStartingIndex + 1);
                    for (int i = e.OldStartingIndex; i < coda.Count; ++i)
                    {
                        coda[i].Number = number;
                        ++number;
                    }

                    break;
                }
                case NotifyCollectionChangedAction.Move:
                {
                    int i1, i2;
                    if (e.OldStartingIndex < e.NewStartingIndex)
                    {
                        i1 = e.OldStartingIndex;
                        i2 = e.NewStartingIndex;
                    }
                    else
                    {
                        i1 = e.NewStartingIndex;
                        i2 = e.OldStartingIndex;
                    }
                    ushort number = (ushort)(i1 + 1);
                    for (int i = i1; i <= i2; ++i)
                    {
                        coda[i].Number = number;
                        ++number;
                    }

                    break;
                }
                case NotifyCollectionChangedAction.Replace:
                {
                    bool invalid = false;
                    ushort number = (ushort)(e.OldStartingIndex + 1);

                    foreach (MeasureElement measure in e.NewItems)
                    {
                        if (measure.FindOwner<CompositionElement>() != this)
                        {
                            coda.Remove(measure);
                            invalid = true;
                        }
                        else
                        {
                            measure.Number = number;
                            ++number;
                        }
                    }

                    if (invalid)
                        throw new InvalidOperationException("The measures added to the CompositionElement's Coda collection must be owned by this CompositionElement!");

                    break;
                }
            }
        }

        #endregion

        #region Internal Methods

        /// <summary>
        /// Adds a music section that presents this composition to the referencing sections collection.
        /// </summary>
        /// <param name="section">
        /// <para>
        /// Type: <see cref="MusicSectionElement"/>
        /// </para>
        /// <para>
        /// The added section.
        /// </para>
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// The <paramref name="section"/> is <see langword="null"/>.
        /// </exception>
        internal void AddReferencingSection(MusicSectionElement section)
        {
            if (section == null)
                throw new ArgumentNullException("section");

            referencingSections.Add(new MusicSectionReferenceElement(PackagePart as CompositionPart, this, section));
        }

        /// <summary>
        /// Removes a music section from the referencing sections collection.
        /// </summary>
        /// <param name="section">
        /// <para>
        /// Type: <see cref="MusicSectionElement"/>
        /// </para>
        /// <para>
        /// The removed section.
        /// </para>
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// The <paramref name="section"/> is <see langword="null"/>.
        /// </exception>
        internal void RemoveReferencingSection(MusicSectionElement section)
        {
            if (section == null)
                throw new ArgumentNullException("section");

            var reference = referencingSections.FirstOrDefault(sr => sr.SectionID == section.ID);
            if (reference != null)
                referencingSections.Remove(reference);
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Adds a new legato element to the composition.
        /// </summary>
        /// <param name="start">
        /// <para>
        /// Type: <see cref="ChordElement"/>
        /// </para>
        /// <para>
        /// The first connected chord.
        /// </para>
        /// </param>
        /// <param name="end">
        /// <para>
        /// Type: <see cref="ChordElement"/>
        /// </para>
        /// <para>
        /// The last connected chord.
        /// </para>
        /// </param>
        /// <returns>
        /// <para>
        /// Type: <see cref="LegatoElement"/>
        /// </para>
        /// <para>
        /// The created legato element.
        /// </para>
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// The <paramref name="start"/> or <paramref name="end"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// The <paramref name="start"/> or <paramref name="end"/> does not belong to this composition.
        /// </exception>
        public LegatoElement AddLegato(ChordElement start, ChordElement end)
        {
            if (start == null)
                throw new ArgumentNullException("start");
            if (end == null)
                throw new ArgumentNullException("end");
            if (start.FindOwner<CompositionElement>() != this)
                throw new ArgumentException("Both symbols must belong to this composition.", "start");
            if (end.FindOwner<CompositionElement>() != this)
                throw new ArgumentException("Both symbols must belong to this composition.", "end");

            var part = (CompositionPart)PackagePart;
            part.RaiseGlobalChangePending(start.FindOwner<MeasureElement>(), end.FindOwner<MeasureElement>());
            var legato = new LegatoElement(part, this, start, end);
            connectors.Add(legato);

            return legato;
        }

        /// <summary>
        /// Creates a new <see cref="MeasureElement"/> in this composition.
        /// </summary>
        /// <returns>
        /// <para>
        /// Type: <see cref="MeasureElement"/>
        /// </para>
        /// <para>
        /// The created measure.
        /// </para>
        /// </returns>
        public MeasureElement CreateMeasure()
        {
            return new MeasureElement(PackagePart as CompositionPart, this);
        }

        /// <summary>
        /// Creates a new <see cref="PartDescriptorElement"/> in this composition.
        /// </summary>
        /// <param name="name">
        /// <para>
        /// Type: <see cref="System.String"/>
        /// </para>
        /// <para>
        /// The name of the new part.
        /// </para>
        /// </param>
        /// <returns>
        /// <para>
        /// Type: <see cref="PartDescriptorElement"/>
        /// </para>
        /// <para>
        /// The created part descriptor.
        /// </para>
        /// </returns>
        public PartDescriptorElement CreatePartDescriptor(string name)
        {
            return new PartDescriptorElement(PackagePart as CompositionPart, this, name);
        }

        /// <summary>
        /// Gets the list of page parts that present the measures inside a given range of this composition.
        /// </summary>
        /// <param name="firstMeasure">
        /// <para>
        /// Type: <see cref="MeasureElement"/>
        /// </para>
        /// <para>
        /// The first measure.
        /// </para>
        /// </param>
        /// <param name="lastMeasure">
        /// <para>
        /// Type: <see cref="MeasureElement"/>
        /// </para>
        /// <para>
        /// The last measure.
        /// </para>
        /// </param>
        /// <returns>
        /// <para>
        /// Type: <see cref="List{T}"/> of <see cref="MusicSectionReferenceElement"/>
        /// </para>
        /// <para>
        /// The list of references to page parts that present measures inside the given range.
        /// </para>
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// The <paramref name="firstMeasure"/> or the <paramref name="lastMeasure"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// The <paramref name="firstMeasure"/> or the <paramref name="lastMeasure"/> is not owned by this composition.<br/>
        /// -or-<br/>
        /// The first measure has a greater number than the last measure.
        /// </exception>
        public List<MusicSectionReferenceElement> GetReferencingPages(MeasureElement firstMeasure, MeasureElement lastMeasure)
        {
            if (firstMeasure == null)
                throw new ArgumentNullException("firstMeasure");
            if (lastMeasure == null)
                throw new ArgumentNullException("lastMeasure");
            if (firstMeasure.FindOwner<CompositionElement>() != this || lastMeasure.FindOwner<CompositionElement>() != this)
                throw new ArgumentException("The measure has to be owned by this composition.");
            if (firstMeasure.Number > lastMeasure.Number)
                throw new ArgumentException("The first measure has a greater number than the last measure.");

            var result = new List<MusicSectionReferenceElement>();

            var sections = (from reference in referencingSections
                            where (reference.FirstMeasure.Number >= firstMeasure.Number ? reference.FirstMeasure.Number <= lastMeasure.Number : firstMeasure.Number <= reference.LastMeasure.Number)
                            select reference).Distinct();
            foreach (var r in sections)
                result.Add(r);

            return result;
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets the measure with a given number.
        /// </summary>
        /// <param name="measureNumber">
        /// <para>
        /// Type: <see cref="UInt16"/>
        /// </para>
        /// <para>
        /// The number (1-based index) of the requested measure.
        /// </para>
        /// </param>
        /// <returns>
        /// <para>
        /// Type: <see cref="MeasureElement"/>
        /// </para>
        /// <para>
        /// The measure with the given number.
        /// </para>
        /// </returns>
        /// <exception cref="ArgumentOutOfRangeException">
        /// The <paramref name="measureNumber"/> is less than 1 or greater than <see cref="MeasuresCount"/>.
        /// </exception>
        public MeasureElement this[ushort measureNumber]
        {
            get 
            {
                if (measureNumber < 1 || measureNumber > MeasuresCount)
                    throw new ArgumentOutOfRangeException("measureNumber");

                if (measureNumber <= measures.Count)
                    return measures[measureNumber - 1];
                else
                    return coda[measureNumber - measures.Count - 1];
            }
        }

        /// <summary>
        /// Gets the collection of measures that form the coda of this composition.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="ElementCollection{T}"/> of <see cref="MeasureElement"/>
        /// </para>
        /// <para>
        /// The collection of measures that form the coda of this composition.
        /// These measures are not a part of the <see cref="Measures"/> collection.
        /// However, the numbering of the measures continues from the <see cref="Measures"/> collection
        /// (i.e. the first measure in the <see cref="Coda"/> has the <see cref="MeasureElement.Number"/> equal
        /// to the <see cref="MeasureElement.Number"/> of the last measure in the <see cref="Measures"/> collection + 1.
        /// </para>
        /// </value>
        public ElementCollection<MeasureElement> Coda
        {
            get { return coda; }
        }

        /// <summary>
        /// Gets or sets the measure where the coda sign is placed.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="MeasureElement"/>
        /// </para>
        /// <para>
        /// The measure where the coda sign is placed.
        /// This value can be <see langword="null"/> if the composition does not have a coda.
        /// </para>
        /// </value>
        /// <exception cref="ValidationException">
        /// The <paramref name="value"/> is not a measure from the <see cref="Measures"/> collection.
        /// </exception>
        /// TODO: Write validation rules
        public MeasureElement CodaSign
        {
            get { return codaSign; }
            set
            {
                ValidateAndThrow("CodaSign", value);

                var firstAffected = codaSign ?? value;
                var lastAffected = value ?? codaSign;
                if (firstAffected != null && lastAffected != null)
                    (PackagePart as CompositionPart).RaiseGlobalChangePending(firstAffected, lastAffected);

                codaSign = value;
                if (codaSign != null)
                    codaAttribute.Value = codaSign.Number.ToString(PackageVocabulary.PackageCulture.NumberFormat);
                else
                    codaAttribute.Value = "0";
            }
        }

        /// <summary>
        /// Gets the composer(s) of this composition.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="ElementCollection{T}"/> of <see cref="PersonElement"/>
        /// </para>
        /// <para>
        /// The collection of composer(s) of this composition.
        /// </para>
        /// </value>
        public ElementCollection<PersonElement> Composers
        {
            get { return composers; }
        }

        /// <summary>
        /// Gets the collection of connectors.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="ElementCollection{T}"/> of <see cref="ConnectorElement"/>
        /// </para>
        /// <para>
        /// The collection of connectors.
        /// </para>
        /// </value>
        public ElementCollection<ConnectorElement> Connectors
        {
            get { return connectors; }
        }

        /// <summary>
        /// Gets or sets the date when the composition was created.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="string"/>
        /// </para>
        /// <para>
        /// The date of the composition's creation.
        /// </para>
        /// </value>
        public string Date
        {
            get { return dateAttribute.Value; }
            set
            {
                dateAttribute.Value = SecurityElement.Escape(value);

                RaisePropertyChanged("Date");
            }
        }

        /// <summary>
        /// Gets or sets the description of the composition.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="string"/>
        /// </para>
        /// <para>
        /// The description of the composition.
        /// </para>
        /// </value>
        public string Description
        {
            get { return descriptionElement.InnerText; }
            set
            {
                descriptionElement.InnerText = SecurityElement.Escape(value);

                RaisePropertyChanged("Description");
            }
        }

        /// <summary>
        /// Gets or sets the measure where the Fine sign is placed.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="MeasureElement"/>
        /// </para>
        /// <para>
        /// The measure where the Fine sign is placed.
        /// This value can be <see langword="null"/> if the composition does not have a Fine.
        /// </para>
        /// </value>
        /// <exception cref="ValidationException">
        /// The <paramref name="value"/> is not a measure from the <see cref="Measures"/> collection.
        /// </exception>
        /// TODO: Write validation rules
        public MeasureElement Fine
        {
            get { return fine; }
            set
            {
                ValidateAndThrow("Fine", value);

                var firstAffected = fine ?? value;
                var lastAffected = value ?? fine;
                if (firstAffected != null && lastAffected != null)
                    (PackagePart as CompositionPart).RaiseGlobalChangePending(firstAffected, lastAffected);

                fine = value;
                if (fine != null)
                    fineAttribute.Value = fine.Number.ToString(PackageVocabulary.PackageCulture.NumberFormat);
                else
                    fineAttribute.Value = "0";
            }
        }

        /// <summary>
        /// Gets the lyricist(s) of this composition.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="ElementCollection{T}"/> of <see cref="PersonElement"/>
        /// </para>
        /// <para>
        /// The collection of person(s) that have written lyrics for this composition.
        /// </para>
        /// </value>
        public ElementCollection<PersonElement> Lyricists
        {
            get { return lyricists; }
        }

        /// <summary>
        /// Gets the collection of measures in the composition.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="ElementCollection{T}"/> of <see cref="MeasureElement"/>
        /// </para>
        /// <para>
        /// The collection of measures of this composition.
        /// </para>
        /// </value>
        public ElementCollection<MeasureElement> Measures
        {
            get { return measures; }
        }

        /// <summary>
        /// Gets the total number of the measures in this composition.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="UInt16"/>
        /// </para>
        /// <para>
        /// The total number of measures in this composition (the sum of <see cref="Measures"/>.Count + <see cref="Coda"/>.Count).
        /// </para>
        /// </value>
        public ushort MeasuresCount
        {
            get { return (ushort)(measures.Count + coda.Count); }
        }

        /// <summary>
        /// Gets the collection of parts in the composition.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="ElementCollection{T}"/> of <see cref="PartDescriptorElement"/>
        /// </para>
        /// <para>
        /// The collection of part descriptors that describe the parts of this composition.
        /// </para>
        /// </value>
        public ElementCollection<PartDescriptorElement> Parts
        {
            get { return parts; }
        }

        /// <summary>
        /// Gets the collection of repetitions in the composition.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="ReadOnlyCollection{T}"/> of <see cref="RepetitionElement"/>
        /// </para>
        /// <para>
        /// The collection of repetitions in this composition.
        /// </para>
        /// </value>
        public ReadOnlyCollection<RepetitionElement> Repetitions
        {
            get { return repetitions; }
        }

        /// <summary>
        /// Gets or sets the measure where the Segno sign is placed.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="MeasureElement"/>
        /// </para>
        /// <para>
        /// The measure where the Segno sign is placed.
        /// This value can be <see langword="null"/> if the composition does not have a Segno.
        /// </para>
        /// </value>
        /// <exception cref="ValidationException">
        /// The <paramref name="value"/> is not a measure from the <see cref="Measures"/> collection.
        /// </exception>
        /// TODO: Write the validation rules
        public MeasureElement Segno
        {
            get { return segno; }
            set
            {
                ValidateAndThrow("Segno", value);

                var firstAffected = segno ?? value;
                var lastAffected = value ?? segno;
                if (firstAffected != null && lastAffected != null)
                    (PackagePart as CompositionPart).RaiseGlobalChangePending(firstAffected, lastAffected);

                segno = value;
                if (segno != null)
                    segnoAttribute.Value = segno.Number.ToString(PackageVocabulary.PackageCulture.NumberFormat);
                else
                    segnoAttribute.Value = "0";

                RaisePropertyChanged("Segno");
            }
        }

        /// <summary>
        /// Gets or sets the sub title of the composition.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="string"/>
        /// </para>
        /// <para>
        /// The sub title of the composition.
        /// </para>
        /// </value>
        public string SubTitle
        {
            get { return subTitleAttribute.Value; }
            set
            {
                subTitleAttribute.Value = SecurityElement.Escape(value);

                RaisePropertyChanged("SubTitle");
            }
        }

        /// <summary>
        /// Gets or sets the title of the composition.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="string"/>
        /// </para>
        /// <para>
        /// The title of the composition.
        /// </para>
        /// </value>
        public string Title
        {
            get { return titleAttribute.Value; }
            set
            {
                titleAttribute.Value = SecurityElement.Escape(value);

                RaisePropertyChanged("Title");
            }
        }

        #endregion

        #region Private Fields

        /// <summary>
        /// Holds the XML attribute that holds the value of the <see cref="CodaSign"/> property.
        /// </summary>
        private XmlAttribute codaAttribute;
        /// <summary>
        /// Holds the value of the <see cref="Coda"/> property.
        /// </summary>
        private ElementCollection<MeasureElement> coda;
        /// <summary>
        /// Holds the value of the <see cref="CodaSign"/> property.
        /// </summary>
        private MeasureElement codaSign;
        /// <summary>
        /// Holds the XML element that holds the <see cref="coda"/> collection.
        /// </summary>
        private XmlElement codaElement;
        /// <summary>
        /// Holds the value of the <see cref="Composers"/> property.
        /// </summary>
        private ElementCollection<PersonElement> composers;
        /// <summary>
        /// Holds the XML element that holds the <see cref="Composers"/> collection.
        /// </summary>
        private XmlElement composersElement;
        /// <summary>
        /// Holds the value of the <see cref="Connectors"/> property.
        /// </summary>
        private ElementCollection<ConnectorElement> connectors;
        /// <summary>
        /// Holds the XML element that holds the <see cref="Connectors"/> collection.
        /// </summary>
        private XmlElement connectorsElement;
        /// <summary>
        /// Holds the value of the <see cref="Date"/> property.
        /// </summary>
        private XmlAttribute dateAttribute;
        /// <summary>
        /// Holds the value of the <see cref="Description"/> property.
        /// </summary>
        private XmlElement descriptionElement;
        /// <summary>
        /// Holds the value of the <see cref="Fine"/> property.
        /// </summary>
        private MeasureElement fine;
        /// <summary>
        /// Holds the XML attribute that holds the value of the <see cref="XmlAttribute"/>.
        /// </summary>
        private XmlAttribute fineAttribute;
        /// <summary>
        /// Holds the value of the <see cref="Lyricists"/> property.
        /// </summary>
        private ElementCollection<PersonElement> lyricists;
        /// <summary>
        /// Holds the XML element that holds the <see cref="Lyricists"/> collection.
        /// </summary>
        private XmlElement lyricistsElement;
        /// <summary>
        /// Holds the value of the <see cref="Measures"/> property.
        /// </summary>
        private ElementCollection<MeasureElement> measures;
        /// <summary>
        /// Holds the XML element that holds the <see cref="measures"/> collection.
        /// </summary>
        private XmlElement measuresElement;
        /// <summary>
        /// Holds the value of the <see cref="Parts"/> property.
        /// </summary>
        private ElementCollection<PartDescriptorElement> parts;
        /// <summary>
        /// Holds the XML element that holds the <see cref="parts"/> collection.
        /// </summary>
        private XmlElement partsElement;
        /// <summary>
        /// Holds the collection of references to music sections that present this composition.
        /// </summary>
        private ElementCollection<MusicSectionReferenceElement> referencingSections;
        /// <summary>
        /// Holds the XML element that holds the <see cref="referencingSections"/> collection.
        /// </summary>
        private XmlElement referencingSectionsElement;
        /// <summary>
        /// Holds the value of the <see cref="Repetitions"/> property.
        /// </summary>
        private ReadOnlyCollection<RepetitionElement> repetitions;
        /// <summary>
        /// Holds the collection of repetitions in the composition.
        /// </summary>
        private ElementCollection<RepetitionElement> repetitionsCollection;
        /// <summary>
        /// Holds the XML element that holds the <see cref="repetitionsCollection"/>.
        /// </summary>
        private XmlElement repetitionsElement;
        /// <summary>
        /// Holds the value of the <see cref="Segno"/> property.
        /// </summary>
        private MeasureElement segno;
        /// <summary>
        /// Holds the XML attribute that holds the value of the <see cref="Segno"/> property.
        /// </summary>
        private XmlAttribute segnoAttribute;
        /// <summary>
        /// Holds the value of the <see cref="SubTitle"/> property.
        /// </summary>
        private XmlAttribute subTitleAttribute;
        /// <summary>
        /// Holds the value of the <see cref="Title"/> property.
        /// </summary>
        private XmlAttribute titleAttribute;

        #endregion
    }

    /// <summary>
    /// Holds a reference to the music section that presents the composition
    /// that owns this element.
    /// </summary>
    public class MusicSectionReferenceElement : ModelElement
    {
        #region Constructors

        /// <summary>
        /// Creates a new <see cref="MusicSectionReferenceElement"/> instance.
        /// </summary>
        /// <param name="packagePart">
        /// <para>
        /// Type: <see cref="CompositionPart"/>
        /// </para>
        /// <para>
        /// The package part that owns this element.
        /// </para>
        /// </param>
        /// <param name="owner">
        /// <para>
        /// Type: <see cref="CompositionElement"/>
        /// </para>
        /// <para>
        /// The composition that directly owns this element.
        /// </para>
        /// </param>
        /// <param name="section">
        /// <para>
        /// Type: <see cref="MusicSectionElement"/>
        /// </para>
        /// <para>
        /// The music section that will be referenced by this element
        /// </para>
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// The <paramref name="owner"/> or the <paramref name="section"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// The <paramref name="section"/> is not owned by a <see cref="PagePart"/>.
        /// </exception>
        public MusicSectionReferenceElement(CompositionPart packagePart, CompositionElement owner, MusicSectionElement section)
            : base(packagePart, owner)
        {
            if (owner == null)
                throw new ArgumentNullException("owner");
            if (section == null)
                throw new ArgumentNullException("section");
            if (section.FindOwner<PageElement>() == null)
                throw new ArgumentException("The referenced section must be owned by a page part.");

            FirstMeasure = section.FirstPresentedMeasure;
            LastMeasure = section.LastPresentedMeasure;
            Page = section.FindOwner<PageElement>().PackagePart as PagePart;
            Section = section;

            pageUriAttribute.Value = Page.Uri.ToString();
            sectionIdAttribute.Value = Section.ID.ToString();

            Section.PropertyChanged += new PropertyChangedEventHandler(Section_PropertyChanged);
        }

        /// <summary>
        /// Creates a new <see cref="MusicSectionReferenceElement"/> instance.
        /// </summary>
        /// <param name="packagePart">
        /// <para>
        /// Type: <see cref="XmlPackagePart"/>
        /// </para>
        /// <para>
        /// The package part that owns this element.
        /// </para>
        /// </param>
        /// <param name="owner">
        /// <para>
        /// Type: <see cref="ModelElement"/>
        /// </para>
        /// <para>
        /// The element that directly owns this element
        /// </para>
        /// </param>
        /// <param name="element">
        /// <para>
        /// Type: <see cref="XmlElement"/>
        /// </para>
        /// <para>
        /// The XML element that holds the serialized data of this element.
        /// </para>
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// Any of the arguments is <see langword="null"/>.
        /// </exception>
        /// <exception cref="SerializationException">
        /// The deserialization of this element has failed.
        /// </exception>
        public MusicSectionReferenceElement(XmlPackagePart packagePart, ModelElement owner, XmlElement element)
            : base(packagePart, owner, element)
        {
            firstMeasureAttribute = element.Attributes[PackageVocabulary.FirstMeasureAttribute];
            lastMeasureAttribute = element.Attributes[PackageVocabulary.LastMeasureAttribute];
            pageUriAttribute = element.Attributes[PackageVocabulary.UriAttribute];
            sectionIdAttribute = element.Attributes[PackageVocabulary.IDRefAttribute];

            var fid = new Guid(firstMeasureAttribute.Value);
            var lid = new Guid(lastMeasureAttribute.Value);
            firstMeasure = packagePart.Package.IDMap.FindObject<MeasureElement>(fid);
            lastMeasure = packagePart.Package.IDMap.FindObject<MeasureElement>(lid);
        }

        #endregion

        #region ModelElement Members

        /// <inheritdoc/>
        protected override XmlElement CreateObjectElement(XmlDocument document)
        {
            var element = document.CreateElement(
                PackageVocabulary.PackageNamespacePrefix,
                PackageVocabulary.MusicSectionElementName,
                PackageVocabulary.PackageNamespaceUri
                );

            firstMeasureAttribute = document.CreateAttribute(PackageVocabulary.FirstMeasureAttribute);
            lastMeasureAttribute = document.CreateAttribute(PackageVocabulary.LastMeasureAttribute);
            pageUriAttribute = document.CreateAttribute(PackageVocabulary.UriAttribute);
            sectionIdAttribute = document.CreateAttribute(PackageVocabulary.IDRefAttribute);

            element.Attributes.Append(firstMeasureAttribute);
            element.Attributes.Append(lastMeasureAttribute);
            element.Attributes.Append(pageUriAttribute);
            element.Attributes.Append(sectionIdAttribute);

            return element;
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// Occurs when the value of a property of the referenced section has changed.
        /// </summary>
        /// <remarks>
        /// <b>Operation:</b><br/>
        /// If the modified property is <see cref="MusicSectionElement.FirstPresentedMeasure"/>
        /// or <see cref="MusicSectionElement.LastPresentedMeasure"/> the handler updates
        /// the <see cref="FirstMeasure"/> and <see cref="LastMeasure"/> properties.
        /// </remarks>
        /// <param name="sender">Object that has sent the event</param>
        /// <param name="e">Event data</param>
        private void Section_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "FirstPresentedMeasure")
                FirstMeasure = Section.FirstPresentedMeasure;
            else if (e.PropertyName == "LastPresentedMeasure")
                 LastMeasure = Section.LastPresentedMeasure;
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Gets the virtual path to the page part that owns the referenced section.
        /// </summary>
        /// <returns>
        /// <para>
        /// Type: <see cref="String"/>
        /// </para>
        /// <para>
        /// The virtual path (relative to the scores directory) to the page part
        /// that owns the referenced section.
        /// </para>
        /// </returns>
        public string GetPageVirtualPath()
        {
            var uriString = pageUriAttribute.Value.Substring(0, pageUriAttribute.Value.LastIndexOf('/'));
            var scoreUri = new Uri(uriString + PackageVocabulary.ScorePartUri, UriKind.Relative);
            var scorePart = (ScorePart)PackagePart.Package.GetPart(scoreUri);
            var projectPart = PackagePart.Package.ProjectPart;

            return projectPart.Project.Scores[scoreUri] + "/" + scorePart.Score.Pages[PageUri];
        }

        /// <summary>
        /// Loads the page part that contains the referenced section into memory.
        /// </summary>
        public void Load()
        {
            if (Page == null)
            {
                var sid = new Guid(sectionIdAttribute.Value);

                Page = (PagePart)PackagePart.Package.GetPart(PageUri);
                Section = (MusicSectionElement)Page.Page.Sections.First(s => s.ID == sid);
                Section.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(Section_PropertyChanged);
            }
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets the first measure presented by the referenced section.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="MeasureElement"/>
        /// </para>
        /// <para>
        /// The first measure presented by the referenced section.
        /// </para>
        /// </value>
        public MeasureElement FirstMeasure
        {
            get { return firstMeasure; }
            private set
            {
                firstMeasure = value;
                firstMeasureAttribute.Value = firstMeasure.ID.ToString();

                RaisePropertyChanged("FirstMeasure");
            }
        }

        /// <summary>
        /// Gets the last measure presented by the referenced section.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="MeasureElement"/>
        /// </para>
        /// <para>
        /// The last measure presented by the referenced section.
        /// </para>
        /// </value>
        public MeasureElement LastMeasure
        {
            get { return lastMeasure; }
            private set
            {
                lastMeasure = value;
                lastMeasureAttribute.Value = lastMeasure.ID.ToString();

                RaisePropertyChanged("LastMeasure");
            }
        }

        /// <summary>
        /// Gets the URI of the page part that owns the referenced section.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="Uri"/>
        /// </para>
        /// <para>
        /// The URI of the page part that owns the referenced section.
        /// </para>
        /// </value>
        public Uri PageUri
        {
            get { return new Uri(pageUriAttribute.Value, UriKind.Relative); }
        }

        /// <summary>
        /// Gets the page part that owns the referenced section.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="PagePart"/>
        /// </para>
        /// <para>
        /// Reference to the page part that owns the referenced section.
        /// This value is <see langword="null"/> if the part has not yet
        /// been loaded.
        /// </para>
        /// </value>
        public PagePart Page
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the referenced section.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="MusicSectionElement"/>
        /// </para>
        /// <para>
        /// The referenced section.
        /// This value is <see langword="null"/> if the owner part 
        /// has not yet been loaded.
        /// </para>
        /// </value>
        public MusicSectionElement Section
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the identifier of the referenced section.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="Guid"/>
        /// </para>
        /// <para>
        /// The identifier of the referenced section.
        /// </para>
        /// </value>
        public Guid SectionID
        {
            get { return new Guid(sectionIdAttribute.Value); }
        }

        #endregion

        #region Private Fields

        /// <summary>
        /// The first measure presented by the referenced section.
        /// </summary>
        private MeasureElement firstMeasure;
        /// <summary>
        /// The XML attribute that holds the ID
        /// of the first measure presented by the referenced section.
        /// </summary>
        private XmlAttribute firstMeasureAttribute;
        /// <summary>
        /// The last measure presented by the referenced section.
        /// </summary>
        private MeasureElement lastMeasure;
        /// <summary>
        /// The XML attribute that holds the ID
        /// of the last measure presented by the referenced section.
        /// </summary>
        private XmlAttribute lastMeasureAttribute;
        /// <summary>
        /// The XML attribute that holds the URI of the page part
        /// that owns the referenced section.
        /// </summary>
        private XmlAttribute pageUriAttribute;
        /// <summary>
        /// The XML attribute that holds the ID of the referenced section.
        /// </summary>
        private XmlAttribute sectionIdAttribute;

        #endregion
    }
}
